package com.hunantv.mglive.utils;

import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.RemoteException;

import com.alibaba.fastjson.JSON;
import com.hunantv.mglive.common.BuildConfig;
import com.hunantv.mglive.common.MaxApplication;
import com.hunantv.mglive.data.ResultModel;
import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;

import org.json.JSONException;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by QiuDa on 15/11/28.
 */
public class HttpUtils {
    private final HashMap<String, Object> mRequestLit = new HashMap<>();
    private static final String TAG = "HttpUtils";
    public static final MediaType TYPE_JSON
            = MediaType.parse("application/json; charset=utf-8");
    private OkHttpClient client = new OkHttpClient();
    private callBack mCall;
    private Context mContext;

    private static long mTokenInvalidTime = 0;//用户会话过期time
    private static long mAppUpdateTime = 0;//提示app升级time

    private ExecutorService LIMITED_TASK_EXECUTOR = Executors.newFixedThreadPool(7);

    public HttpUtils(Context context, callBack call) {
        this.mContext = context;
        this.mCall = call;
    }


    /**
     * 请求处理
     *
     * @param requestModel requestMode对象
     * @return ResultModel
     */
    private ResultModel processRequest(RequestModel requestModel) {
        Request request = requestModel.getRequest();
        ResultModel resultModel = new ResultModel();
        resultModel.setParam(requestModel.getParam());
        resultModel.setTag(requestModel.getTag());
        try {
            resultModel.setUrl(request.urlString());
            Response response = client.newCall(request).execute();
            if (response == null) {
                resultModel.setResponseCode(ResultModel.ERROR_CODE_RESULT);
                resultModel.setE(new Exception("网络异常，请检查网络连接"));
                resultModel.setMsg("网络异常，请检查网络连接");
                return resultModel;
            }
            String resultjson = response.body().string();
            L.d(TAG, "processRequest-response  " + response.request().urlString() + "   __RESULT:  " + resultjson);
            if (response.code() == 200) {
                if (!StringUtil.isNullorEmpty(resultjson)) {
                    try {
                        resultModel = JSON.parseObject(resultjson, ResultModel.class);
                        resultModel.setUrl(request.urlString());
                        resultModel.setParam(requestModel.getParam());
                        resultModel.setTag(requestModel.getTag());
                        if(StringUtil.isNullorEmpty(resultModel.getCode()) && StringUtil.isNullorEmpty(resultModel.getData()))
                        {
                            //处理非芒果通用格式的返回{code:"",msg:"",data:""}
                            resultModel.setCode("200");
                            resultModel.setData(resultjson);
                        }
                    } catch (Exception e) {
                        L.e(TAG, e);
                        resultModel.setE(e);
                        resultModel.setMsg("网络异常，请检查网络连接");
                        resultModel.setResponseCode(ResultModel.ERROR_CODE_PARSE);
                    }
                } else {
                    resultModel.setResponseCode(ResultModel.ERROR_CODE_RESULT);
                }
            } else {
                resultModel.setE(new Exception("网络异常，请检查网络连接"));
                resultModel.setMsg("网络异常，请检查网络连接");
                resultModel.setResponseCode(ResultModel.ERROR_CODE_REQUEST + response.code());
            }

            if (StringUtil.isNullorEmpty(resultModel.getCode())) {
                resultModel.setCode(resultModel.getErr_code());
                resultModel.setMsg(resultModel.getErr_msg());
            }
            if ("0".equals(resultModel.getCode()) || "200".equals(resultModel.getCode())) {
                if (null != mCall) {
                    Object obj = mCall.asyncExecute(request.urlString(), resultModel);
                    resultModel.setDataModel(obj);
                }
            }
        } catch (IOException e) {
            if (!StringUtil.isNullorEmpty(e.getMessage()) && e.getMessage().equals("Canceled")) {
                return resultModel;
            }
            resultModel.setCode(null);
            resultModel.setResponseCode(ResultModel.ERROR_CODE_CONNECT);
            resultModel.setE(new Exception("网络异常，请检查网络连接"));
            resultModel.setMsg("网络异常，请检查网络连接");
        } catch (Exception e1) {
            L.e(TAG, e1);
            resultModel.setCode(null);
            resultModel.setResponseCode(ResultModel.ERROR_CODE_PARSE);
            resultModel.setE(new Exception("网络异常，请检查网络连接"));
            resultModel.setMsg("网络异常，请检查网络连接");
        }
        return resultModel;
    }

    /**
     * 处理请求结果
     *
     * @param resultModel 请求结果
     */
    private void processResult(ResultModel resultModel) {
        if (null == mCall) {
            return;
        }
        if (resultModel.getE() != null) {
            mCall.onError(resultModel.getUrl(), resultModel.getE());
        }

        try {
            if ("0".equals(resultModel.getCode()) || "200".equals(resultModel.getCode()) || "200".equals(resultModel.getErr_code())) {
                mCall.onSucceed(resultModel.getUrl(), resultModel);
                if(StringUtil.isNullorEmpty(resultModel.getResponseCode())){//无业务错误
                    //点播、直播的上报
                    if (BuildConfig.URL_GET_LIVE_PLAY_URL.contains(resultModel.getUrl()) || BuildConfig.URL_LIVE_GET_URL.contains(resultModel.getUrl())) {
                        report(resultModel.getUrl(), resultModel.getParam(), "", "1", true);
                    } else if (BuildConfig.URL_GET_VIDEO_URL.contains(resultModel.getUrl())) {
                        report(resultModel.getUrl(), resultModel.getParam(), "", "0", true);
                    }
                }else{//有业务错误
                    //点播、直播的上报
                    if (BuildConfig.URL_GET_LIVE_PLAY_URL.contains(resultModel.getUrl()) || BuildConfig.URL_LIVE_GET_URL.contains(resultModel.getUrl())) {
                        report(resultModel.getUrl(), resultModel.getParam(), resultModel.getResponseCode(), "1", true);
                    } else if (BuildConfig.URL_GET_VIDEO_URL.contains(resultModel.getUrl())) {
                        report(resultModel.getUrl(), resultModel.getParam(), resultModel.getResponseCode(), "0", true);
                    }
                }

            } else if ("1301".equals(resultModel.getCode())) {
                if (System.currentTimeMillis() - mTokenInvalidTime > 1000 * 10) {
                    //处理会话过期
                    Toast.makeText(mContext, resultModel.getMsg(), Toast.LENGTH_SHORT).show();
                    MaxApplication.getInstance().logout();

                    MGTVUtil.getInstance().login(MaxApplication.getAppContext());
                    mTokenInvalidTime = System.currentTimeMillis();
                }
            } else {//Http错误
                mCall.onFailure(resultModel.getUrl(), resultModel);
                //点播、直播的上报
                if (BuildConfig.URL_GET_LIVE_PLAY_URL.contains(resultModel.getUrl()) || BuildConfig.URL_LIVE_GET_URL.contains(resultModel.getUrl())) {
                    report(resultModel.getUrl(), resultModel.getParam(), resultModel.getResponseCode(), "1", false);
                } else if (BuildConfig.URL_GET_VIDEO_URL.contains(resultModel.getUrl())) {
                    report(resultModel.getUrl(), resultModel.getParam(),resultModel.getResponseCode(), "0", false);
                }
            }
        } catch (Exception e) {
            L.e(TAG, e);
            if (mCall != null) {
              mCall.onError(resultModel.getUrl(), resultModel.getE());
            }

            //点播、直播的上报
            if (BuildConfig.URL_GET_LIVE_PLAY_URL.contains(resultModel.getUrl()) || BuildConfig.URL_LIVE_GET_URL.contains(resultModel.getUrl())) {
                report(resultModel.getUrl(), resultModel.getParam(), resultModel.getResponseCode(), "1", false);
            } else if (BuildConfig.URL_GET_VIDEO_URL.contains(resultModel.getUrl())) {
                report(resultModel.getUrl(), resultModel.getParam(),resultModel.getResponseCode(), "0", false);
            }

        }
    }

    private void report(String url, Map<String, String> paramMap, String code, String videoType, boolean succeed) {
        String param = StringUtil.urlJoint(url, paramMap);
        ReportUtil.instance().report(url, param, videoType, "1", code, succeed);
    }

    /**
     * 设置回调
     *
     * @param call call
     */
    public void setCallBack(callBack call) {
        this.mCall = call;
    }

    /**
     * 取消所有请求
     */
    public void cancelAll() {
        synchronized (mRequestLit) {
            mRequestLit.clear();
        }
        new Thread() {
            @Override
            public void run() {
                super.run();
                if (client != null) {
                    client.cancel(mContext);
                }
            }
        }.start();
    }

    /**
     * get
     *
     * @param url   url
     * @param param 参数
     * @return 是否发起请求
     */
    public boolean get(String url, Map<String, String> param) {
        return get(url, param, null, null);
    }

    /**
     * get
     *
     * @param url    url
     * @param param  参数
     * @param header 头
     * @return 是否发起请求
     */
    public boolean get(String url, Map<String, String> param, Map<String, String> header) {
        return get(url, param, header, null);
    }

    /**
     * get
     *
     * @param url   url
     * @param param 参数
     * @param tag   tag
     * @return 是否发起请求
     */
    public boolean get(String url, Map<String, String> param, Object tag) {
        return get(url, param, null, tag);
    }

    /**
     * get
     *
     * @param url    url
     * @param param  参数
     * @param header 头
     * @param tag    tag
     * @return 是否发起请求
     */
    public boolean get(String url, Map<String, String> param, Map<String, String> header, Object tag) {
        synchronized (mRequestLit) {
            if (mRequestLit.containsKey(url)) {
                return false;
            }
            url = StringUtil.urlJoint(url, param);// 拼接url
            mRequestLit.put(url, "");
        }
        if (param == null) {
            param = new HashMap<>();
            Random random = new Random();
            String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date()) + Math.abs(random.nextLong() % 1000000);
            param.put("seqId", date);
        }
        RequestModel requestModel = new RequestModel();
        requestModel.setTag(tag);
        requestModel.setParam(param);

        Request.Builder builder
                = new Request.Builder()
                .url(url).tag(mContext);
        if (header != null) {
            for (String key : header.keySet()) {
                builder.addHeader(key, header.get(key));
            }
        }
        Request request = builder.build();
        requestModel.setRequest(request);
        HttpAsync async = new HttpAsync();
        async.executeOnExecutor(LIMITED_TASK_EXECUTOR, requestModel);
        return true;
    }

    /**
     * post
     *
     * @param url   url
     * @param param 参数
     * @return 是否发起请求
     */
    public boolean post(String url, Map<String, String> param) {
        return post(url, param, null, null);
    }

    /**
     * post
     *
     * @param url    url
     * @param param  参数
     * @param header 头
     * @return 是否发起请求
     */
    public boolean post(String url, Map<String, String> param, Map<String, String> header) {
        return post(url, param, header, null);
    }

    /**
     * post
     *
     * @param url   url
     * @param param 参数
     * @param tag   tag
     * @return 是否发起请求
     */
    public boolean post(String url, Map<String, String> param, Object tag) {
        return post(url, param, null, tag);
    }

    /**
     * Post方法
     *
     * @param url    请求url
     * @param param  请求参数
     * @param header 头
     * @param tag    tag
     * @return 结果
     */
    public boolean post(String url, Map<String, String> param, Map<String, String> header, Object tag) {
        synchronized (mRequestLit) {
            if (mRequestLit.containsKey(url)) {
                return false;
            }
            mRequestLit.put(url, "");
        }
        RequestModel requestModel = new RequestModel();
        requestModel.setTag(tag);
        requestModel.setParam(param);

        FormEncodingBuilder formEncodingBuilder = new FormEncodingBuilder();
        if (param == null) {
            param = new HashMap<>();
            param.put("seqId", getSeqId());
        }
        for (String key : param.keySet()) {
            formEncodingBuilder.add(key, param.get(key));
        }
        Request.Builder builder = new Request.Builder()
                .url(url).tag(mContext)
                .post(formEncodingBuilder.build());

        if (header != null) {
            for (String key : header.keySet()) {
                builder.addHeader(key, header.get(key));
            }
        }

        Request request = builder.build();
        requestModel.setRequest(request);

        HttpAsync async = new HttpAsync();
        async.executeOnExecutor(LIMITED_TASK_EXECUTOR, requestModel);
        return true;
    }


    private String getSeqId() {
        int value = (int) ((Math.random() * 9 + 1) * 100000);
        return new SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date()) + value;
    }

    class HttpAsync extends AsyncTask<RequestModel, Integer, ResultModel> {

        private RequestModel mRequestModel;

        @Override
        protected ResultModel doInBackground(RequestModel... params) {
            if (mCall == null || params == null || params.length == 0) {
                return null;
            }
            mRequestModel = params[0];
            return processRequest(mRequestModel);
        }


        @Override
        protected void onPostExecute(ResultModel result) {

            processResult(result);

            synchronized (mRequestLit) {
                if (result != null)  //todo: maxxiang, 连不上server时，result为空，会crash.
                    mRequestLit.remove(result.getUrl());
            }
        }
    }


    class RequestModel {

        private Request request;
        private Map<String, String> param;
        private Object tag;

        public Request getRequest() {
            return request;
        }

        public void setRequest(Request requestBody) {
            this.request = requestBody;
        }

        public Map<String, String> getParam() {
            return param;
        }

        public void setParam(Map<String, String> param) {
            this.param = param;
        }

        public Object getTag() {
            return tag;
        }

        public void setTag(Object tag) {
            this.tag = tag;
        }
    }

    public interface callBack {
        /**
         * 异步处理（同步get调用才有效）
         *
         * @param url         url
         * @param resultModel 结果对象
         */
        Object asyncExecute(String url, ResultModel resultModel);

        /**
         * 请求成功
         *
         * @param url         url
         * @param resultModel 结果对象
         */
        void onSucceed(String url, ResultModel resultModel) throws JSONException, RemoteException;

        /**
         * 请求错误
         *
         * @param url url
         * @param e   错误
         */
        void onError(String url, Exception e);

        /**
         * 请求失败
         *
         * @param url         url
         * @param resultModel 结果对象
         */
        void onFailure(String url, ResultModel resultModel);

        /**
         * get请求
         *
         * @param url   url
         * @param param 参数
         */
        boolean get(String url, Map<String, String> param);

        /**
         * post请求
         *
         * @param url   url
         * @param param 参数
         */
        boolean post(String url, Map<String, String> param);
    }

}
